home *** CD-ROM | disk | FTP | other *** search
/ SGI Freeware 2002 November / SGI Freeware 2002 November - Disc 2.iso / dist / fw_glimpse.idb / usr / freeware / src / glimpse-3.0 / agrep / newmgrep.c.z / newmgrep.c
C/C++ Source or Header  |  1997-09-09  |  63KB  |  1,827 lines

  1. /* Copyright (c) 1994 Sun Wu, Udi Manber, Burra Gopal.  All Rights Reserved. */
  2.  
  3. /* multipattern matcher */
  4.  
  5. #include <stdio.h>
  6. #include <ctype.h>
  7. #include <sys/stat.h>
  8. #include "agrep.h"
  9. #include <sys/time.h>
  10.  
  11. #define ddebug
  12. #define uchar unsigned char
  13. #undef    MAXPAT
  14. #define MAXPAT  256
  15. #undef    MAXLINE
  16. #define MAXLINE 1024
  17. #undef    MAXSYM
  18. #define MAXSYM  256
  19. #define MAXMEMBER1 32768
  20. /* #define MAXMEMBER1 262144 */ /*2^18 */ 
  21. #define MAXPATFILE 600000
  22. #define BLOCKSIZE  16384
  23. #define MAXHASH    32768 
  24. /* #define MAXHASH    262144 */
  25. #define mask5        32767
  26. #define max_num    40000
  27. #if    ISO_CHAR_SET
  28. #define W_DELIM       256
  29. #else
  30. #define W_DELIM       128
  31. #endif
  32. #define L_DELIM    10 
  33. #define Hbits 5 /* how much to shift to perform the hash */
  34.  
  35. extern int LIMITOUTPUT, LIMITPERFILE;
  36. extern int BYTECOUNT, PRINTOFFSET, PRINTRECORD, CurrentByteOffset;
  37. extern int MULTI_OUTPUT;    /* used by glimpse only if OR, never for AND */
  38. extern int DELIMITER;
  39. extern CHAR D_pattern[MaxDelimit*2];
  40. extern int D_length;
  41. extern CHAR tc_D_pattern[MaxDelimit*2];
  42. extern int tc_D_length;
  43. extern COUNT, FNAME, SILENT, FILENAMEONLY, prev_num_of_matched, num_of_matched;
  44. extern INVERSE, OUTTAIL;
  45. extern WORDBOUND, WHOLELINE, NOUPPER;
  46. extern ParseTree *AParse;
  47. extern int AComplexPattern;
  48. extern unsigned char  CurrentFileName[], Progname[]; 
  49. extern total_line;
  50. extern agrep_initialfd;
  51. extern int EXITONERROR;
  52. extern int PRINTPATTERN;
  53. extern int agrep_inlen;
  54. extern CHAR *agrep_inbuffer;
  55. extern FILE *agrep_finalfp;
  56. extern int agrep_outpointer;
  57. extern int agrep_outlen;
  58. extern CHAR * agrep_outbuffer;
  59. extern int errno;
  60. extern int NEW_FILE, POST_FILTER;
  61.  
  62. extern int tuncompressible();
  63. extern int quick_tcompress();
  64. extern int quick_tuncompress();
  65. extern int TCOMPRESSED;
  66. extern int EASYSEARCH;
  67. extern char FREQ_FILE[MAX_LINE_LEN], HASH_FILE[MAX_LINE_LEN], STRING_FILE[MAX_LINE_LEN];
  68. extern char PAT_FILE_NAME[MAX_LINE_LEN];
  69.  
  70. uchar SHIFT1[MAXMEMBER1];
  71.  
  72. int   LONG  = 0;
  73. int   SHORT = 0;
  74. int   p_size= 0;
  75.  
  76. uchar tr[MAXSYM];
  77. uchar tr1[MAXSYM];
  78. int   HASH[MAXHASH];
  79. int   Hash2[max_num];
  80. uchar *PatPtr[max_num];
  81. uchar *pat_spool = NULL; /* [MAXPATFILE+2*max_num+MAXPAT]; */
  82. uchar *patt[max_num];
  83. int   pat_len[max_num];
  84. int   pat_indices[max_num]; /* pat_indices[p] gives the actual index in matched_teriminals: used only with AParse != 0 */
  85. int num_pat;
  86.  
  87. extern char  amatched_terminals[MAXNUM_PAT]; /* which patterns have been matched in the current line? Used only with AParse != 0, so max_num is not needed */
  88. extern int anum_terminals;
  89. extern int AComplexBoolean;
  90. static void countline();
  91.  
  92. #if    DOTCOMPRESSED
  93. /* Equivalent variables for compression search */
  94. uchar tc_SHIFT1[MAXMEMBER1];
  95.  
  96. int   tc_LONG  = 0;
  97. int   tc_SHORT = 0;
  98. int   tc_p_size= 0;
  99.  
  100. uchar tc_tr[MAXSYM];
  101. uchar tc_tr1[MAXSYM];
  102. int   tc_HASH[MAXHASH];
  103. int   tc_Hash2[max_num];
  104. uchar *tc_PatPtr[max_num];
  105. uchar *tc_pat_spool = NULL; /* [MAXPATFILE+2*max_num+MAXPAT]; */
  106. uchar *tc_patt[max_num];
  107. int   tc_pat_len[max_num];
  108. int   tc_pat_indices[max_num]; /* pat_indices[p] gives the actual index in matched_teriminals: used only with AParse != 0 */
  109. int tc_num_pat;    /* must be the same as num_pat */
  110. #endif    /*DOTCOMPRESSED*/
  111.  
  112. static void f_prep();
  113. static void f_prep1();
  114. static void accumulate();
  115. #if    DOTCOMPRESSED
  116. static void tc_f_prep();
  117. static void tc_f_prep1();
  118. static void tc_accumulate();
  119. #endif
  120.  
  121. #ifdef perf_check
  122.     int cshift=0, cshift0=0, chash=0;
  123. #endif
  124.  
  125. /*
  126.  * General idea behind output processing with delimiters, inverse, compression, etc.
  127.  * CAUTION: In compressed files, we can search ONLY for simple patterns or their ;,.
  128.  * Attempts to search for complex patterns / with errors might lead to spurious matches.
  129.  * 1. Once we find the match, go back and forward to get the delimiters that surround
  130.  *    the matched region.
  131.  * 2. If it is a compressed file, verify that the match is "real" (compressed files
  132.  *    can have pseudo matches hence this filtering step is required).
  133.  * 3. Increment num_of_matched.
  134.  * 4. Process some output options which print stuff before the matched region is
  135.  *    printed.
  136.  * 5. If there is compression, decomress and output the matched region. Otherwise
  137.  *    just output it as is. Remember, from step (1) we know the matched region.
  138.  * 6. If inverse is set, then we must keep track of the end of the last matched region
  139.  *    in the variable lastout. When there is a match, we must print everything from
  140.  *    lastout to the beginning of the current matched region (curtextbegin) and then
  141.  *    update lastout to point to the end of the current matched region (curtextend).
  142.  *    ALSO: if we exit from the main loops, we must output everything from the end
  143.  *    of the last matched region to the end of the input buffer.
  144.  * 7. Delimiter handling in complex patterns is different: there the search is done
  145.  *    for a boolean and of the delimiter pattern and the actual pattern.
  146.  * 8. For convenience and speed, the multipattern matching routines to handle
  147.  *    compressed files have been separated from their (normal) counterparts.
  148.  * 9. One special note on handling complicated boolean patterns: the parse
  149.  *    tree will be the same for both compressed and uncomrpessed patterns and the
  150.  *    same amatched_terminals array will be used in both. BUT, the pat_spool and
  151.  *    pat_index, etc., will be different as they refer to the individual terminals.
  152.  */
  153.  
  154. int
  155. prepf(mfp, mbuf, mlen)
  156. int mfp, mlen;
  157. unsigned char *mbuf;
  158. {
  159.     int length=0, i, p=1;
  160.     uchar *pat_ptr;
  161.     unsigned Mask = 31;
  162.     int num_read;
  163.     unsigned char *buf;
  164.     struct stat stbuf;
  165.     int j, k;    /* to implement \\ */
  166.  
  167.         if ((mfp == -1) && ((mbuf == NULL) || (mlen <= 0))) return -1;
  168.  
  169.     if (mfp != -1) {
  170.         if (fstat(mfp, &stbuf) == -1) {
  171.             fprintf(stderr, "%s: cannot stat file: %s\n", Progname, PAT_FILE_NAME);
  172.             return -1;
  173.         }
  174.         if (!S_ISREG(stbuf.st_mode)) {
  175.             fprintf(stderr, "%s: pattern file not regular file: %s\n", Progname, PAT_FILE_NAME);
  176.             return -1;
  177.         }
  178.         if (stbuf.st_size*2 > MAXPATFILE + 2*max_num) {
  179.             fprintf(stderr, "%s: pattern file too large (> %d B): %s\n", Progname, (MAXPATFILE+2*max_num)/2, PAT_FILE_NAME);
  180.             return -1;
  181.         }
  182.         if (pat_spool != NULL) free(pat_spool);
  183.         pat_ptr = pat_spool = (unsigned char *)malloc(stbuf.st_size*2 + MAXPAT);
  184.         alloc_buf(mfp, &buf, MAXPATFILE+2*BLOCKSIZE);
  185.         while((num_read = fill_buf(mfp, buf+length, 2*BLOCKSIZE)) > 0) {
  186.             length = length + num_read;
  187.             if(length > MAXPATFILE) {
  188.                 fprintf(stderr, "%s: maximum pattern file size is %d\n", Progname, MAXPATFILE);
  189.                                 if (!EXITONERROR) {
  190.                                         errno = AGREP_ERROR;
  191.                                         free_buf(mfp, buf);
  192.                                         return -1;
  193.                                 }
  194.                                 else exit(2);
  195.             }
  196.         }
  197.     }
  198.     else {
  199.         buf = mbuf;
  200.         length = mlen;
  201.         if (mlen*2 > MAXPATFILE + 2*max_num) {
  202.             fprintf(stderr, "%s: pattern buffer too large (> %d B)\n", Progname, (MAXPATFILE+2*max_num)/2);
  203.             return -1;
  204.         }
  205.         if (pat_spool != NULL) free(pat_spool);
  206.         pat_ptr = pat_spool = (unsigned char *)malloc(mlen*2 + MAXPAT);
  207.     }
  208.  
  209.     /* Now all the patterns are in buf */
  210.     buf[length] = '\n';
  211.     i=0; p=1;
  212. /* removed by Udi 11/8/94 - we now do WORDBOUND "by hand" 
  213.     if(WORDBOUND) {
  214.         while(i<length) {
  215.             patt[p] = pat_ptr;
  216.             *pat_ptr++ = W_DELIM;
  217.             while((i<length) && ((*pat_ptr = buf[i++]) != '\n')) pat_ptr++;
  218.             *pat_ptr++ = W_DELIM;
  219.             *pat_ptr++ = 0;
  220.             p++;
  221.         }
  222.     }
  223.     else
  224. */
  225.     if(WHOLELINE) {
  226.         while(i<length) {
  227.             patt[p] = pat_ptr;
  228.             *pat_ptr++ = L_DELIM;
  229.             while((i<length) && ((*pat_ptr = buf[i++]) != '\n')) pat_ptr++;
  230.             *pat_ptr++ = L_DELIM;
  231.             *pat_ptr++ = 0;
  232.             p++;
  233.         }
  234.     }
  235.     else {
  236.         while(i < length) {
  237.             patt[p] = pat_ptr;
  238.             while((i<length) && ((*pat_ptr = buf[i++]) != '\n')) pat_ptr++;
  239.             *pat_ptr++ = 0;
  240.             p++;  
  241.         }
  242.     }
  243.  
  244.     /* Now, the patterns have been copied into patt[] */
  245.     if(p>max_num) {
  246.         fprintf(stderr, "%s: maximum number of patterns is %d\n", Progname, max_num); 
  247.                 if (!EXITONERROR) {
  248.                         errno = AGREP_ERROR;
  249.                         free_buf(mfp, buf);
  250.                         return -1;
  251.                 }
  252.                 else exit(2);
  253.  
  254.     }
  255.  
  256.     for(i=1; i<20; i++) *pat_ptr = i;  /* boundary safety zone */
  257.  
  258.     /* I might have to keep changing tr s.t. mgrep won't get confused with W_DELIM */
  259.     for(i=0; i< MAXSYM; i++) tr[i] = i;
  260.     if(NOUPPER) {
  261.                 for (i=0; i<MAXSYM; i++)
  262.                         if (isupper(i)) tr[i] = tr[tolower(i)];
  263.         /* for(i='A'; i<= 'Z'; i++) tr[i] = i + 'a' - 'A'; */
  264.     }
  265. /*
  266.     if(WORDBOUND) {
  267.         for(i=1; i<MAXSYM; i++) if(!isalnum(i)) tr[i] = W_DELIM;
  268.     }
  269. removed by Udi 11/8/94 - the trick of using W-delim was too buggy.
  270. we now do it "by hand" after we find a match 
  271. */
  272.     for(i=0; i< MAXSYM; i++) tr1[i] = tr[i]&Mask;
  273.     num_pat =  p-1;
  274.     p_size  =  MAXPAT;
  275.     for(i=1; i<=num_pat; i++) {
  276.         p = strlen(patt[i]);
  277.         if ((patt[i][0] == '^') || (patt[i][0] == '$')) patt[i][0] = '\n';
  278.         if ((p > 1) && ((patt[i][p-1] == '^') || (patt[i][p-1] == '$')) && (patt[i][p-2] != '\\')) patt[i][p-1] = '\n';
  279.  
  280.         /* Added by bg, Dec 2nd 1994 */
  281.         for (k=0; k<p; k++) {
  282.             if (patt[i][k] == '\\') {
  283.                 for (j=k; j<p; j++)
  284.                     patt[i][j] = patt[i][j+1]; /* including '\0' */
  285.                 p--;
  286.             }
  287.         }
  288.  
  289.         pat_len[i] = p;
  290.         /*
  291.         pat_len[i] = (WORDBOUND?(p-2>0?p-2:1):p);  changed by Udi 11/8/94
  292.         */
  293. #ifdef    debug
  294.         printf("prepf(): patt[%d]=%s, pat_len[%d]=%d\n", i, patt[i], i, pat_len[i]);
  295. #endif
  296.         if(p!=0 && p < p_size) p_size = p;    /* MIN */
  297.     }
  298.     if(p_size == 0) {
  299.         fprintf(stderr, "%s: the pattern file is empty\n", Progname);
  300.                 if (!EXITONERROR) {
  301.                         errno = AGREP_ERROR;
  302.                         free_buf(mfp, buf);
  303.                         return -1;
  304.                 }
  305.                 else exit(2);
  306.     }
  307.     if(length > 400 && p_size > 2) LONG = 1;
  308.     if(p_size == 1) SHORT = 1;
  309.     for(i=0; i<MAXMEMBER1; i++) SHIFT1[i] = p_size - 1 - LONG;
  310.     for(i=0; i<MAXHASH; i++) {
  311.         HASH[i] = 0;
  312.     }
  313.     for(i=1; i<=num_pat; i++) f_prep(i, patt[i]);
  314.     accumulate();
  315.     memset(pat_indices, '\0', sizeof(int) * (num_pat + 1));
  316.     for(i=1; i<=num_pat; i++) f_prep1(i, patt[i]);
  317.  
  318. #if    DOTCOMPRESSED
  319.     /* prepf for compression */
  320.     if (-1 == tc_prepf(buf, length)) {
  321.         free_buf(mfp, buf);
  322.         return -1;
  323.     }
  324. #endif    /*DOTCOMPRESSED*/
  325.         free_buf(mfp, buf);
  326.         return 0;
  327. }
  328.  
  329. #if    DOTCOMPRESSED
  330. /*
  331.  * Compression equivalent of prepf: called right after prepf.
  332.  * 1. Read patt and SHIFT1
  333.  * 2. Call tcompress on the patterns in patt and put in tc_patt.
  334.  * 3. Use these patterns to compute tc_SHIFT (ignore WDELIM, LDELIM, case sensitivity, etc.)
  335.  * 4. Process other variables/functions (pat_spool, tr, tr1, pat_len, accumulate, SHIFT1, f_prep, f_prep1, pat_indices) appropriately.
  336.  */
  337. int
  338. tc_prepf(buf, length)
  339. unsigned char *buf;
  340. int    length;
  341. {
  342.     int i, p=1;
  343.     uchar *pat_ptr;
  344.     unsigned Mask = 31;
  345.     int tc_length;
  346.     unsigned char tc_buf[MAXPAT * 2];    /* maximum length of the compressed pattern */
  347.     static struct timeval initt, finalt;
  348.  
  349.     if (length*2 > MAXPATFILE + 2*max_num) {
  350.         fprintf(stderr, "%s: pattern buffer too large (> %d B)\n", Progname, (MAXPATFILE+2*max_num)/2);
  351.         return -1;
  352.     }
  353.     if (tc_pat_spool != NULL) free(tc_pat_spool);
  354.     pat_ptr = tc_pat_spool = (unsigned char *)malloc(length*2 + MAXPAT);
  355.  
  356. #if    MEASURE_TIMES
  357.     gettimeofday(&initt, NULL);
  358. #endif    /*MEASURE_TIMES*/
  359.  
  360.     i=0; p=1;
  361.     while(i < length) {
  362.         tc_patt[p] = pat_ptr;
  363.         while((*pat_ptr = buf[i++]) != '\n') pat_ptr++;
  364.         *pat_ptr++ = 0;
  365.         if ((tc_length = quick_tcompress(FREQ_FILE, HASH_FILE, tc_patt[p], strlen(tc_patt[p]), tc_buf, MAXPAT * 2 - 8, TC_EASYSEARCH)) > 0) {
  366.             memcpy(tc_patt[p], tc_buf, tc_length);
  367.             tc_patt[p][tc_length] = '\0';
  368.             pat_ptr = tc_patt[p] + tc_length + 1;    /* character after '\0' */
  369.         }
  370.         p++;  
  371.     }
  372.  
  373.     for(i=1; i<20; i++) *pat_ptr = i;  /* boundary safety zone */
  374.  
  375.     /* Ignore all other options: it is automatically W_DELIM */
  376.     for(i=0; i< MAXSYM; i++) tc_tr[i] = i;
  377.     for(i=0; i< MAXSYM; i++) tc_tr1[i] = tc_tr[i]&Mask;
  378.     tc_num_pat =  p-1;
  379.     tc_p_size  =  MAXPAT;
  380.     for(i=1; i<=num_pat; i++) {
  381.         p = strlen(tc_patt[i]);
  382.         tc_pat_len[i] = p;
  383. #ifdef    debug
  384.         printf("prepf(): tc_patt[%d]=%s, tc_pat_len[%d]=%d\n", i, tc_patt[i], i, tc_pat_len[i]);
  385. #endif
  386.         if(p!=0 && p < tc_p_size) tc_p_size = p;    /* MIN */
  387.     }
  388.     if(tc_p_size == 0) {    /* cannot happen NOW */
  389.         fprintf(stderr, "%s: the pattern file is empty\n", Progname);
  390.                 if (!EXITONERROR) {
  391.                         errno = AGREP_ERROR;
  392.                         return -1;
  393.                 }
  394.                 else exit(2);
  395.     }
  396.     if(length > 400 && tc_p_size > 2) tc_LONG = 1;
  397.     if(tc_p_size == 1) tc_SHORT = 1;
  398.     for(i=0; i<MAXMEMBER1; i++) tc_SHIFT1[i] = tc_p_size - 1 - LONG;
  399.     for(i=0; i<MAXHASH; i++) {
  400.         tc_HASH[i] = 0;
  401.     }
  402.     for(i=1; i<=tc_num_pat; i++) tc_f_prep(i, tc_patt[i]);
  403.     tc_accumulate();
  404.     memset(tc_pat_indices, '\0', sizeof(int) * (tc_num_pat + 1));
  405.     for(i=1; i<=tc_num_pat; i++) tc_f_prep1(i, tc_patt[i]);
  406.  
  407. #if    MEASURE_TIMES
  408.     gettimeofday(&finalt, NULL);
  409.     INFILTER_ms +=  (finalt.tv_sec*1000 + finalt.tv_usec/1000) - (initt.tv_sec*1000 + initt.tv_usec/1000);
  410. #endif    /*MEASURE_TIMES*/
  411.         return 0;
  412. }
  413. #endif    /*DOTCOMPRESSED*/
  414.  
  415. int
  416. mgrep(fd)
  417. int fd;
  418.     register char r_newline = '\n';
  419.     unsigned char *text;
  420.     register int buf_end, num_read, start, end, residue = 0;
  421.     int    oldCurrentByteOffset;
  422.     int    first_time = 1;
  423.  
  424. #if     AGREP_POINTER
  425.         if (fd != -1) {
  426. #endif  /*AGREP_POINTER*/
  427.                 alloc_buf(fd, &text, 2*BLOCKSIZE+MAXLINE);
  428.         text[MAXLINE-1] = '\n';  /* initial case */
  429.         start = MAXLINE;
  430.  
  431.         while( (num_read = fill_buf(fd, text+MAXLINE, 2*BLOCKSIZE)) > 0) 
  432.         {
  433.             buf_end = end = MAXLINE + num_read -1 ;
  434.             oldCurrentByteOffset = CurrentByteOffset;
  435.  
  436.             if (first_time) {
  437.                 if ((TCOMPRESSED == ON) && tuncompressible(text+MAXLINE, num_read)) {
  438.                     EASYSEARCH = text[MAXLINE+SIGNATURE_LEN-1];
  439.                     start += SIGNATURE_LEN;
  440.                     CurrentByteOffset += SIGNATURE_LEN;
  441.                     if (!EASYSEARCH) {
  442.                         fprintf(stderr, "not compressed for easy-search: can miss some matches in: %s\n", CurrentFileName);
  443.                     }
  444.                 }
  445.                 else TCOMPRESSED = OFF;
  446.                 first_time = 0;
  447.             }
  448.  
  449.             if (!DELIMITER) {
  450.                 while(text[end]  != r_newline && end > MAXLINE) end--;
  451.                 text[start-1] = r_newline;
  452.             }
  453.             else {
  454.                 unsigned char *newbuf = text + end + 1;
  455.                 newbuf = backward_delimiter(newbuf, text+MAXLINE, D_pattern, D_length, OUTTAIL);    /* see agrep.c/'d' */
  456.                 if (newbuf < text+MAXLINE+D_length) newbuf = text + end + 1;
  457.                 end = newbuf - text - 1;
  458.                 memcpy(text+start-D_length, D_pattern, D_length);
  459.             }
  460.             residue = buf_end - end  + 1 ;
  461.             if(INVERSE && COUNT) countline(text+MAXLINE, num_read);
  462.  
  463.             /* MGREP_PROCESS */
  464.             if (TCOMPRESSED) {    /* separate functions since separate globals => too many if-statements within a single function makes it slow */
  465. #if    DOTCOMPRESSED
  466.                 if(tc_SHORT) { if (-1 == tc_m_short(text, start, end)) {free_buf(fd, text); return -1;}}
  467.                 else      { if (-1 == tc_monkey1(text, start, end)) {free_buf(fd, text); return -1;}}
  468. #endif    /*DOTCOMPRESSED*/
  469.             }
  470.             else {
  471.                 if(SHORT) { if (-1 == m_short(text, start, end)) {free_buf(fd, text); return -1;}}
  472.                 else      { if (-1 == monkey1(text, start, end)) {free_buf(fd, text); return -1;}}
  473.             }
  474.                         if(FILENAMEONLY && (num_of_matched - prev_num_of_matched) && (NEW_FILE || !POST_FILTER)) {
  475.                                 if (agrep_finalfp != NULL)
  476.                                         fprintf(agrep_finalfp, "%s\n", CurrentFileName);
  477.                                 else {
  478.                                         int outindex;
  479.                                         for(outindex=0; (outindex+agrep_outpointer<agrep_outlen) &&
  480.                                                         (CurrentFileName[outindex] != '\0'); outindex++) {
  481.                                                 agrep_outbuffer[agrep_outpointer+outindex] = CurrentFileName[outindex];
  482.                                         }
  483.                                         if ((CurrentFileName[outindex] != '\0') || (outindex+agrep_outpointer+1>=agrep_outlen)) {
  484.                                                 OUTPUT_OVERFLOW;
  485.                                                 free_buf(fd, text);
  486.                                                 return -1;
  487.                                         }
  488.                                         else {
  489.                                                 agrep_outbuffer[agrep_outpointer+outindex++] = '\n';
  490.                                         }
  491.                                         agrep_outpointer += outindex;
  492.                                 }
  493.                                 free_buf(fd, text);
  494.                                 NEW_FILE = OFF;
  495.                                 return 0;
  496.                         }
  497.  
  498.             CurrentByteOffset = oldCurrentByteOffset + end - start + 1;
  499.             start = MAXLINE - residue;
  500.             if(start < 0) {
  501.                 start = 1; 
  502.             }
  503.             strncpy(text+start, text+end, residue);
  504.  
  505.             if (((LIMITOUTPUT > 0) && (LIMITOUTPUT <= num_of_matched)) ||
  506.                 ((LIMITPERFILE > 0) && (LIMITPERFILE <= num_of_matched - prev_num_of_matched))) {
  507.                 free_buf(fd, text);
  508.                 return 0;    /* done */
  509.             }
  510.         } /* end of while(num_read = ... */
  511.         if (!DELIMITER) {
  512.             text[start-1] = '\n';
  513.             text[start+residue] = '\n';
  514.         }
  515.         else {
  516.             if (start > D_length) memcpy(text+start-D_length, D_pattern, D_length);
  517.             memcpy(text+start+residue, D_pattern, D_length);
  518.         }
  519.         end = start + residue;
  520.         if(residue > 1) {
  521.             if (TCOMPRESSED) {
  522. #if    DOTCOMPRESSED
  523.                 if(tc_SHORT) tc_m_short(text, start, end);
  524.                 else      tc_monkey1(text, start, end);
  525. #endif    /*DOTCOMPRESSED*/
  526.             }
  527.             else {
  528.                 if(SHORT) m_short(text, start, end);
  529.                 else      monkey1(text, start, end);
  530.             }
  531.                         if(FILENAMEONLY && (num_of_matched - prev_num_of_matched) && (NEW_FILE || !POST_FILTER)) {
  532.                                 if (agrep_finalfp != NULL)
  533.                                         fprintf(agrep_finalfp, "%s\n", CurrentFileName);
  534.                                 else {
  535.                                         int outindex;
  536.                                         for(outindex=0; (outindex+agrep_outpointer<agrep_outlen) &&
  537.                                                         (CurrentFileName[outindex] != '\0'); outindex++) {
  538.                                                 agrep_outbuffer[agrep_outpointer+outindex] = CurrentFileName[outindex];
  539.                                         }
  540.                                         if ((CurrentFileName[outindex] != '\0') || (outindex+agrep_outpointer+1>=agrep_outlen)) {
  541.                                                 OUTPUT_OVERFLOW;
  542.                                                 free_buf(fd, text);
  543.                                                 return -1;
  544.                                         }
  545.                                         else {
  546.                                                 agrep_outbuffer[agrep_outpointer+outindex++] = '\n';
  547.                                         }
  548.                                         agrep_outpointer += outindex;
  549.                                 }
  550.                                 free_buf(fd, text);
  551.                                 NEW_FILE = OFF;
  552.                                 return 0;
  553.                         }
  554.         }
  555.         free_buf(fd, text);
  556.         return (0);
  557. #if    AGREP_POINTER
  558.     }
  559.     else {
  560.                 text = (unsigned char *)agrep_inbuffer;
  561.                 num_read = agrep_inlen;
  562.                 start = 0;
  563.                 buf_end = end = num_read - 1;
  564.  
  565.             oldCurrentByteOffset = CurrentByteOffset;
  566.  
  567.             if (first_time) {
  568.                 if ((TCOMPRESSED == ON) && tuncompressible(text+MAXLINE, num_read)) {
  569.                     EASYSEARCH = text[MAXLINE+SIGNATURE_LEN-1];
  570.                     start += SIGNATURE_LEN;
  571.                     CurrentByteOffset += SIGNATURE_LEN;
  572.                     if (!EASYSEARCH) {
  573.                         fprintf(stderr, "not compressed for easy-search: can miss some matches in: %s\n", CurrentFileName);
  574.                     }
  575.                 }
  576.                 else TCOMPRESSED = OFF;
  577.                 first_time = 0;
  578.             }
  579.  
  580.             if (!DELIMITER)
  581.                 while(text[end]  != r_newline && end > 1) end--;
  582.             else {
  583.                                 unsigned char *newbuf = text + end + 1;
  584.                                 newbuf = backward_delimiter(newbuf, text, D_pattern, D_length, OUTTAIL);        /* see agrep.c/'d' */
  585.                 if (newbuf < text+D_length) newbuf = text + end + 1;
  586.                                 end = newbuf - text - 1;
  587.             }
  588.             /* text[0] = text[end] = r_newline; : the user must ensure that the delimiter is there at text[0] and occurs somewhere before text[end] */
  589.  
  590.             if (INVERSE && COUNT) countline(text, num_read);
  591.  
  592.                         /* An exact copy of the above MGREP_PROCESS */
  593.             if (TCOMPRESSED) {    /* separate functions since separate globals => too many if-statements within a single function makes it slow */
  594. #if    DOTCOMPRESSED
  595.                 if(tc_SHORT) { if (-1 == tc_m_short(text, start, end)) {free_buf(fd, text); return -1;}}
  596.                 else      { if (-1 == tc_monkey1(text, start, end)) {free_buf(fd, text); return -1;}}
  597. #endif    /*DOTCOMPRESSED*/
  598.             }
  599.             else {
  600.                 if(SHORT) { if (-1 == m_short(text, start, end)) {free_buf(fd, text); return -1;}}
  601.                 else      { if (-1 == monkey1(text, start, end)) {free_buf(fd, text); return -1;}}
  602.             }
  603.                         if(FILENAMEONLY && (num_of_matched - prev_num_of_matched) && (NEW_FILE || !POST_FILTER)) {
  604.                                 if (agrep_finalfp != NULL)
  605.                                         fprintf(agrep_finalfp, "%s\n", CurrentFileName);
  606.                                 else {
  607.                                         int outindex;
  608.                                         for(outindex=0; (outindex+agrep_outpointer<agrep_outlen) &&
  609.                                                         (CurrentFileName[outindex] != '\0'); outindex++) {
  610.                                                 agrep_outbuffer[agrep_outpointer+outindex] = CurrentFileName[outindex];
  611.                                         }
  612.                                         if ((CurrentFileName[outindex] != '\0') || (outindex+agrep_outpointer+1>=agrep_outlen)) {
  613.                                                 OUTPUT_OVERFLOW;
  614.                                                 free_buf(fd, text);
  615.                                                 return -1;
  616.                                         }
  617.                                         else {
  618.                                                 agrep_outbuffer[agrep_outpointer+outindex++] = '\n';
  619.                                         }
  620.                                         agrep_outpointer += outindex;
  621.                                 }
  622.                                 free_buf(fd, text);
  623.                                 NEW_FILE = OFF;
  624.                                 return 0;
  625.                         }
  626.  
  627.                 return 0;
  628.     }
  629. #endif    /*AGREP_POINTER*/
  630. #ifdef perf_check
  631.     fprintf(stderr,"Shifted %d times; shift=0 %d times; hash was = %d times\n",cshift, cshift0, chash);
  632.     return 0;
  633. #endif
  634. } /* end mgrep */
  635.  
  636. static void
  637. countline(text, len)
  638. unsigned char *text; int len;
  639. {
  640. int i;
  641.     for (i=0; i<len; i++) if(text[i] == '\n') total_line++;
  642. }
  643.  
  644. /* Stuff that always needs to be printed whenever there is a match in all functions in this file */
  645. int
  646. print_options(pat_index, text, curtextbegin, curtextend)
  647.     int    pat_index;
  648.     unsigned char    *text, *curtextbegin, *curtextend;
  649. {
  650.     int    PRINTED = 0;
  651.     if(FNAME && (NEW_FILE || !POST_FILTER)) {
  652.         char    nextchar = (POST_FILTER == ON)?'\n':' ';
  653.         char    *prevstring = (POST_FILTER == ON)?"\n":"";
  654.         if (agrep_finalfp != NULL)
  655.             fprintf(agrep_finalfp, "%s%s:%c", prevstring, CurrentFileName, nextchar);
  656.         else {
  657.             int outindex;
  658.             if (prevstring[0] != '\0') {
  659.                 if(agrep_outpointer + 1 >= agrep_outlen) {
  660.                     OUTPUT_OVERFLOW;
  661.                     return -1;
  662.                 }
  663.                 else agrep_outbuffer[agrep_outpointer ++] = prevstring[0];
  664.             }
  665.             for(outindex=0; (outindex+agrep_outpointer<agrep_outlen) &&
  666.                     (CurrentFileName[outindex] != '\0'); outindex++) {
  667.                 agrep_outbuffer[agrep_outpointer+outindex] = CurrentFileName[outindex];
  668.             }
  669.             if ((CurrentFileName[outindex] != '\0') || (outindex+agrep_outpointer+2>=agrep_outlen)) {
  670.                 OUTPUT_OVERFLOW;
  671.                 return -1;
  672.             }
  673.             else {
  674.                 agrep_outbuffer[agrep_outpointer+outindex++] = ':';
  675.                 agrep_outbuffer[agrep_outpointer+outindex++] = nextchar;
  676.             }
  677.             agrep_outpointer += outindex;
  678.         }
  679.         NEW_FILE = OFF;
  680.         PRINTED = 1;
  681.     }
  682.  
  683.     if (PRINTPATTERN) {
  684.         if (agrep_finalfp != NULL)
  685.             fprintf(agrep_finalfp, "%d- ", pat_index);
  686.         else {
  687.             char s[32];
  688.             int outindex;
  689.             sprintf(s, "%d- ", pat_index);
  690.             for(outindex=0; (outindex+agrep_outpointer<agrep_outlen) &&
  691.                     (s[outindex] != '\0'); outindex++) {
  692.                 agrep_outbuffer[agrep_outpointer+outindex] = s[outindex];
  693.             }
  694.             if (s[outindex] != '\0') {
  695.                 OUTPUT_OVERFLOW;
  696.                 return -1;
  697.             }
  698.             agrep_outpointer += outindex;
  699.         }
  700.         PRINTED = 1;
  701.     }
  702.  
  703.     if (BYTECOUNT) {
  704.         if (agrep_finalfp != NULL)
  705.             fprintf(agrep_finalfp, "%d= ", CurrentByteOffset);
  706.         else {
  707.             char s[32];
  708.             int outindex;
  709.             sprintf(s, "%d= ", CurrentByteOffset);
  710.             for(outindex=0; (outindex+agrep_outpointer<agrep_outlen) &&
  711.                     (s[outindex] != '\0'); outindex++) {
  712.                 agrep_outbuffer[agrep_outpointer+outindex] = s[outindex];
  713.             }
  714.             if (s[outindex] != '\0') {
  715.                 OUTPUT_OVERFLOW;
  716.                 return -1;
  717.             }
  718.             agrep_outpointer += outindex;
  719.         }
  720.         PRINTED = 1;
  721.     }
  722.  
  723.     if (PRINTOFFSET) {
  724.         if (agrep_finalfp != NULL)
  725.             fprintf(agrep_finalfp, "@%d{%d} ", CurrentByteOffset - (text -curtextbegin), curtextend-curtextbegin);
  726.         else {
  727.             char s[32];
  728.             int outindex;
  729.             sprintf(s, "@%d{%d} ", CurrentByteOffset - (text -curtextbegin), curtextend-curtextbegin);
  730.             for (outindex=0; (outindex+agrep_outpointer<agrep_outlen) &&
  731.                      (s[outindex] != '\0'); outindex ++) {
  732.                 agrep_outbuffer[agrep_outpointer+outindex] = s[outindex];
  733.             }
  734.             if (s[outindex] != '\0') {
  735.                 OUTPUT_OVERFLOW;
  736.                 return -1;
  737.             }
  738.             agrep_outpointer += outindex;
  739.         }
  740.         PRINTED = 1;
  741.     }
  742.     return PRINTED;
  743. }
  744.  
  745. int
  746. monkey1( text, start, end  ) 
  747. int start, end; register unsigned char *text;
  748. {
  749.     int PRINTED = 0;
  750.         unsigned char *oldtext;
  751.     int pat_index;
  752.     register uchar *textend;
  753.     unsigned char *textbegin;
  754.     unsigned char *curtextend;
  755.     unsigned char *curtextbegin;
  756.     register unsigned hash;
  757.     register uchar shift;
  758.     register int  m1, Long=LONG;
  759.     int MATCHED=0;
  760.     register uchar *qx;
  761.     register uchar *px;
  762.     register int p, p_end;
  763.     uchar *lastout;
  764.     /* int OUT=0; */
  765.     int hash2;
  766.     int j;
  767.     int DOWITHMASK;
  768.  
  769.     DOWITHMASK = 0;
  770.     if (AParse != 0) memset(amatched_terminals, '\0', anum_terminals);
  771.     textbegin = text + start;
  772.     textend = text + end;
  773.     m1 = p_size-1;
  774.     lastout = text+start;
  775.     text = text + start + m1 -1 ;
  776.     /* -1 to allow match to the first \n in case the pattern has ^ in front of it */
  777. /*
  778.     if (WORDBOUND || WHOLELINE) text = text-1;
  779.     if (WHOLELINE) text = text-1;
  780. */
  781.         /* to accomodate the extra 2 W_delim */
  782.     while (text <= textend) {
  783.         hash=tr1[*text];
  784.         hash=(hash<<Hbits)+(tr1[*(text-1)]);
  785.         if(Long) hash=(hash<<Hbits)+(tr1[*(text-2)]);
  786.         shift = SHIFT1[hash];
  787. #ifdef perf_check
  788.         cshift++;
  789. #endif
  790.         if(shift == 0) {
  791.             hash=hash&mask5;
  792.             hash2 = (tr[*(text-m1)]<<8) + tr[*(text-m1+1)];
  793.             p = HASH[hash];
  794. #ifdef perf_check
  795.             cshift0++;
  796. #endif
  797.             p_end = HASH[hash+1];
  798. #ifdef debug
  799.             printf("hash=%d, p=%d, p_end=%d\n", hash, p, p_end);
  800. #endif
  801.             while(p++ < p_end) {
  802.                 if(hash2 != Hash2[p]) continue;
  803. #ifdef perf_check
  804.                 chash++;
  805. #endif
  806.                 if (((pat_index = pat_indices[p]) <= 0) || (pat_len[pat_index] <= 0)) continue;
  807.                 px = PatPtr[p];
  808.                 qx = text-m1;
  809.                 while((*px!=0)&&(tr[*px] == tr[*qx])) {
  810.                     px++;
  811.                     qx++;
  812.                 }
  813.                 if (*px == 0) {
  814.                     if(text > textend) return 0;
  815.                     if (WORDBOUND) {
  816.                         if (isalnum(*qx)) goto skip_output;
  817.                         if (isalnum(*(text-m1-1))) goto skip_output;
  818.                     }
  819.                     if (!DOWITHMASK) {
  820.                                                 /* Don't update CurrentByteOffset here: only before outputting properly */
  821.                                                 if (!DELIMITER) {
  822.                             curtextbegin = text; while((curtextbegin > textbegin) && (*(--curtextbegin) != '\n'));
  823.                             if (*curtextbegin == '\n') curtextbegin ++;
  824.                             curtextend = text+1; while((curtextend < textend) && (*curtextend != '\n')) curtextend ++;
  825.                             if (*curtextend == '\n') curtextend ++;
  826.                                                 }
  827.                                                 else {
  828.                                                         curtextbegin = backward_delimiter(text, textbegin, D_pattern, D_length, OUTTAIL);
  829.                                                         curtextend = forward_delimiter(text+1, textend, D_pattern, D_length, OUTTAIL);
  830.                                                 }
  831.                         if (!OUTTAIL || INVERSE) textbegin = curtextend;
  832.                         else if (DELIMITER) textbegin = curtextend - D_length;
  833.                         else textbegin = curtextend - 1;
  834.                     }
  835.  
  836.                     DOWITHMASK = 1;
  837.                     amatched_terminals[pat_index - 1] = 1;
  838.                     if (AComplexBoolean) {
  839.                         /* Can output only after all the matches in the current record have been identified: just like filter_output */
  840.                         oldtext = text;
  841.                         CurrentByteOffset += (oldtext + pat_len[pat_index] - 1 - text);
  842.                         text = oldtext + pat_len[pat_index] - 1;
  843.                         MATCHED = 0;
  844.                         goto skip_output;
  845.                     }
  846.                     else if ((long)AParse & AND_EXP) {
  847.                         for (j=0; j<anum_terminals; j++) if (!amatched_terminals[j]) break;
  848.                         if (j<anum_terminals) goto skip_output;
  849.                     }
  850.                     MATCHED=1;
  851.                                         oldtext = text; /* only for MULTI_OUTPUT */
  852.  
  853. #undef    DO_OUTPUT
  854. #define DO_OUTPUT(change_text)\
  855.                     num_of_matched++;\
  856.                     if(FILENAMEONLY || SILENT)  return 0;\
  857.                     if (!COUNT) {\
  858.                         PRINTED = print_options(pat_index, text, curtextbegin, curtextend);\
  859.                         if(!INVERSE) {\
  860.                             if (PRINTRECORD) {\
  861.                             if (agrep_finalfp != NULL) {\
  862.                                 fwrite(curtextbegin, 1, curtextend - curtextbegin, agrep_finalfp);\
  863.                             }\
  864.                             else {\
  865.                                 if (agrep_outpointer + curtextend - curtextbegin>= agrep_outlen) {\
  866.                                     OUTPUT_OVERFLOW;\
  867.                                     return -1;\
  868.                                 }\
  869.                                 else {\
  870.                                     memcpy(agrep_outbuffer + agrep_outpointer, curtextbegin, curtextend-curtextbegin);\
  871.                                     agrep_outpointer += curtextend - curtextbegin;\
  872.                                 }\
  873.                             }\
  874.                             }\
  875.                             else if (PRINTED) {\
  876.                                 if (agrep_finalfp != NULL) fputc('\n', agrep_finalfp);\
  877.                                 else agrep_outbuffer[agrep_outpointer ++] = '\n';\
  878.                                 PRINTED = 0;\
  879.                             }\
  880.                                                         if ((change_text) && MULTI_OUTPUT) {     /* next match starting from end of current */\
  881.                                 CurrentByteOffset += (oldtext + pat_len[pat_index] - 1 - text);\
  882.                                                                 text = oldtext + pat_len[pat_index] - 1;\
  883.                                                                 MATCHED = 0;\
  884.                                                         }\
  885.                             else if (change_text) {\
  886.                                 CurrentByteOffset += textbegin - text;\
  887.                                 text = textbegin;\
  888.                             }\
  889.                         }\
  890.                         else {    /* INVERSE */\
  891.                             /* if(lastout < curtextbegin) OUT=1; */\
  892.                             if (agrep_finalfp != NULL)\
  893.                                 fwrite(lastout, 1, curtextbegin-lastout, agrep_finalfp);\
  894.                             else {\
  895.                                 if (curtextbegin - lastout + agrep_outpointer >= agrep_outlen) {\
  896.                                     OUTPUT_OVERFLOW;\
  897.                                     return -1;\
  898.                                 }\
  899.                                 memcpy(agrep_outbuffer+agrep_outpointer, lastout, curtextbegin-lastout);\
  900.                                 agrep_outpointer += (curtextbegin-lastout);\
  901.                             }\
  902.                             lastout=textbegin;\
  903.                             if (change_text) {\
  904.                                 CurrentByteOffset += textbegin - text;\
  905.                                 text = textbegin;\
  906.                             }\
  907.                         }\
  908.                     }\
  909.                     else if (change_text) {    /* COUNT */\
  910.                         CurrentByteOffset += textbegin - text;\
  911.                         text = textbegin;\
  912.                     }\
  913.                     if (((LIMITOUTPUT > 0) && (LIMITOUTPUT <= num_of_matched)) ||\
  914.                         ((LIMITPERFILE > 0) && (LIMITPERFILE <= num_of_matched - prev_num_of_matched))) return 0;    /* done */\
  915.  
  916.                     DO_OUTPUT(1)
  917.                 }
  918.  
  919.             skip_output:
  920.                                 if (MATCHED && !MULTI_OUTPUT && !AComplexBoolean) break;    /* else look for more possible matches since we never know how many will match */
  921.                 if (DOWITHMASK && (text >= curtextend - 1)) {
  922.                     DOWITHMASK = 0;
  923.                     if (AComplexBoolean && dd(curtextbegin, curtextend) && eval_tree(AParse, amatched_terminals)) {
  924.                         DO_OUTPUT(0)
  925.                     }
  926.                     if (AParse != 0) memset(amatched_terminals, '\0', anum_terminals);
  927.                 }
  928.             }
  929.             /* If I found some match and I am about to cross over a delimiter, then set DOWITHMASK to 0 and zero out the amatched_terminals */
  930.             if (DOWITHMASK && (text >= curtextend - 1)) {
  931.                 DOWITHMASK = 0;
  932.                 if (AComplexBoolean && dd(curtextbegin, curtextend) && eval_tree(AParse, amatched_terminals)) {
  933.                     DO_OUTPUT(0)
  934.                 }
  935.                 if (AParse != 0) memset(amatched_terminals, '\0', anum_terminals);
  936.             }
  937.             if(!MATCHED) shift = 1;    /* || MULTI_OUTPUT is implicit */
  938.             else {
  939.                 MATCHED = 0;
  940.                 shift = m1 - 1 > 0 ? m1 - 1 : 1;
  941.             }
  942.         }
  943.  
  944.         /* If I found some match and I am about to cross over a delimiter, then set DOWITHMASK to 0 and zero out the amatched_terminals */
  945.         if (DOWITHMASK && (text >= curtextend - 1)) {
  946.             DOWITHMASK = 0;
  947.             if (AComplexBoolean && dd(curtextbegin, curtextend) && eval_tree(AParse, amatched_terminals)) {
  948.                 DO_OUTPUT(0)
  949.             }
  950.             if (AParse != 0) memset(amatched_terminals, '\0', anum_terminals);
  951.         }
  952.  
  953.         text += shift;
  954.         CurrentByteOffset += shift;
  955.     }
  956.  
  957.     /* Do residual stuff: check if there was a match at the end of the line | check if rest of the buffer needs to be output due to inverse */
  958.  
  959.     if (DOWITHMASK && (text >= curtextend - 1)) {
  960.         DOWITHMASK = 0;
  961.         if (AComplexBoolean && dd(curtextbegin, curtextend) && eval_tree(AParse, amatched_terminals)) {
  962.             DO_OUTPUT(0)
  963.         }
  964.         if (AParse != 0) memset(amatched_terminals, '\0', anum_terminals);
  965.     }
  966.  
  967.     if(INVERSE && !COUNT && (lastout <= textend)) {
  968.                 if (agrep_finalfp != NULL) {
  969.                         while(lastout <= textend) fputc(*lastout++, agrep_finalfp);
  970.                 }
  971.                 else {
  972.                         if (textend - lastout + 1 + agrep_outpointer >= agrep_outlen) {
  973.                                 OUTPUT_OVERFLOW;
  974.                                 return -1;
  975.                         }
  976.                         memcpy(agrep_outbuffer+agrep_outpointer, lastout, textend-lastout+1);
  977.                         agrep_outpointer += (textend-lastout+1);
  978.                         lastout = textend;
  979.                 }
  980.     }
  981.  
  982.     return 0;
  983. }
  984.  
  985. #if    DOTCOMPRESSED
  986. int
  987. tc_monkey1( text, start, end  ) 
  988. int start, end;
  989. register unsigned char *text;
  990. {
  991.     int PRINTED = 0;
  992.         unsigned char *oldtext;
  993.     int pat_index;
  994.     register uchar *textend;
  995.     unsigned char *textbegin;
  996.     unsigned char *curtextend;
  997.         unsigned char *curtextbegin;
  998.     register unsigned hash;
  999.     register uchar shift;
  1000.     register int  m1, Long=LONG;
  1001.     int MATCHED=0;
  1002.     register uchar *qx;
  1003.     register uchar *px;
  1004.     register int p, p_end;
  1005.     uchar *lastout;
  1006.     /* int OUT=0; */
  1007.     int hash2;
  1008.     int j;
  1009.     int DOWITHMASK;
  1010.     struct timeval initt, finalt;
  1011.     int newlen;
  1012.  
  1013.     DOWITHMASK = 0;
  1014.     if (AParse != 0) memset(amatched_terminals, '\0', anum_terminals);
  1015.     textbegin = text + start;
  1016.     textend = text + end;
  1017.     m1 = tc_p_size-1;
  1018.     lastout = text+start;
  1019.     text = text + start + m1 -1;
  1020.     /* -1 to allow match to the first \n in case the pattern has ^ in front of it */
  1021.     /* WORDBOUND adjustment not required */
  1022.     while (text <= textend) {
  1023.         hash=tc_tr1[*text];
  1024.         hash=(hash<<Hbits)+(tc_tr1[*(text-1)]);
  1025.         if(Long) hash=(hash<<Hbits)+(tc_tr1[*(text-2)]);
  1026.         shift = tc_SHIFT1[hash];
  1027. #ifdef perf_check
  1028.         cshift++;
  1029. #endif
  1030.         if(shift == 0) {
  1031.             hash=hash&mask5;
  1032.             hash2 = (tc_tr[*(text-m1)]<<8) + tc_tr[*(text-m1+1)];
  1033.             p = tc_HASH[hash];
  1034. #ifdef perf_check
  1035.             cshift0++;
  1036. #endif
  1037.             p_end = tc_HASH[hash+1];
  1038. #ifdef debug
  1039.             printf("hash=%d, p=%d, p_end=%d\n", hash, p, p_end);
  1040. #endif
  1041.             while(p++ < p_end) {
  1042.                 if(hash2 != tc_Hash2[p]) continue;
  1043. #ifdef perf_check
  1044.                 chash++;
  1045. #endif
  1046.                 if (((pat_index = tc_pat_indices[p]) <= 0) || (tc_pat_len[pat_index] <= 0)) continue;
  1047.                 px = tc_PatPtr[p];
  1048.                 qx = text-m1;
  1049.  
  1050.                  while((*px!=0)&&(tc_tr[*px] == tc_tr[*qx])) {
  1051.                      px++;
  1052.                      qx++;
  1053.                  }
  1054.                  if (*px == 0) {
  1055.                     if(text > textend) return 0;
  1056.                     if (!DOWITHMASK) {
  1057.                         /* Don't update CurrentByteOffset here: only before outputting properly */
  1058.                         if (!DELIMITER) {
  1059.                             curtextbegin = text; while((curtextbegin > textbegin) && (*(--curtextbegin) != '\n'));
  1060.                             if (*curtextbegin == '\n') curtextbegin ++;
  1061.                             curtextend = text+1; while((curtextend < textend) && (*curtextend != '\n')) curtextend ++;
  1062.                             if (*curtextend == '\n') curtextend ++;
  1063.                         }
  1064.                         else {
  1065.                             curtextbegin = backward_delimiter(text, textbegin, tc_D_pattern, tc_D_length, OUTTAIL);
  1066.                             curtextend = forward_delimiter(text+1, textend, tc_D_pattern, tc_D_length, OUTTAIL);
  1067.                         }
  1068.                     }
  1069.                     /* else prev curtextbegin is OK: if full AND isn't found, DOWITHMASK is 0-ed so that we search at most 1 line below */
  1070. #if    MEASURE_TIMES
  1071.                     gettimeofday(&initt, NULL);
  1072. #endif    /*MEASURE_TIMES*/
  1073.                     /* Was it really a match in the compressed line from prev line in text to text + strlen(tc_pat_len[pat_index]? */
  1074.                     if (-1==exists_tcompressed_word(tc_PatPtr[p], tc_pat_len[pat_index], curtextbegin, text - curtextbegin + tc_pat_len[pat_index], EASYSEARCH))
  1075.                         goto skip_output;
  1076. #if     MEASURE_TIMES
  1077.                     gettimeofday(&finalt, NULL);
  1078.                     FILTERALGO_ms +=  (finalt.tv_sec *1000 + finalt.tv_usec/1000) - (initt.tv_sec*1000 + initt.tv_usec/1000);
  1079. #endif  /*MEASURE_TIMES*/
  1080.                     if (!DOWITHMASK) {
  1081.                         if (!OUTTAIL || INVERSE) textbegin = curtextend;
  1082.                         else if (DELIMITER) textbegin = curtextend - D_length;
  1083.                         else textbegin = curtextend - 1;
  1084.                     }
  1085.                     DOWITHMASK = 1;
  1086.                     amatched_terminals[pat_index-1] = 1;
  1087.                     if (AComplexBoolean) {
  1088.                         /* Can output only after all the matches in the current record have been identified: just like filter_output */
  1089.                         oldtext = text;
  1090.                         CurrentByteOffset += (oldtext + pat_len[pat_index] - 1 - text);
  1091.                         text = oldtext + pat_len[pat_index] - 1;
  1092.                         MATCHED = 0;
  1093.                         goto skip_output;
  1094.                     }
  1095.                     else if ((long)AParse & AND_EXP) {
  1096.                         for (j=0; j<anum_terminals; j++) if (!amatched_terminals[j]) break;
  1097.                         if (j<anum_terminals) goto skip_output;
  1098.                     }
  1099.  
  1100.                     MATCHED=1;
  1101.                                         oldtext = text; /* only for MULTI_OUTPUT */
  1102.  
  1103. #undef    DO_OUTPUT
  1104. #define DO_OUTPUT(change_text)\
  1105.                     num_of_matched++;\
  1106.                     if(FILENAMEONLY || SILENT)  return 0;\
  1107.                     if (!COUNT) {\
  1108.                         PRINTED = print_options(pat_index, text, curtextbegin, curtextend);\
  1109.                         if(!INVERSE) {\
  1110.                             if (PRINTRECORD) {\
  1111. /* #if     MEASURE_TIMES\
  1112.                             gettimeofday(&initt, NULL);\
  1113. #endif  MEASURE_TIMES */\
  1114.                             if (agrep_finalfp != NULL)\
  1115.                                 newlen = quick_tuncompress(FREQ_FILE, STRING_FILE, curtextbegin, curtextend-curtextbegin, agrep_finalfp, -1, EASYSEARCH);\
  1116.                             else {\
  1117.                                 if ((newlen = quick_tuncompress(FREQ_FILE, STRING_FILE, curtextbegin, curtextend-curtextbegin, agrep_outbuffer, agrep_outlen - agrep_outpointer, EASYSEARCH)) > 0) {\
  1118.                                     if (newlen + agrep_outpointer >= agrep_outlen) {\
  1119.                                         OUTPUT_OVERFLOW;\
  1120.                                         return -1;\
  1121.                                     }\
  1122.                                     agrep_outpointer += newlen;\
  1123.                                 }\
  1124.                             }\
  1125. /* #if     MEASURE_TIMES\
  1126.                             gettimeofday(&finalt, NULL);\
  1127.                             OUTFILTER_ms += (finalt.tv_sec* 1000 + finalt.tv_usec/1000) - (initt.tv_sec*1000 + initt.tv_usec/1000);\
  1128. #endif  MEASURE_TIMES */\
  1129.                             }\
  1130.                             else if (PRINTED) {\
  1131.                                 if (agrep_finalfp != NULL) fputc('\n', agrep_finalfp);\
  1132.                                 else agrep_outbuffer[agrep_outpointer ++] = '\n';\
  1133.                                 PRINTED = 0;\
  1134.                             }\
  1135.                                                         if ((change_text) && MULTI_OUTPUT) {     /* next match starting from end of current */\
  1136.                                 CurrentByteOffset += (oldtext + tc_pat_len[pat_index] - 1 - text);\
  1137.                                                                 text = oldtext + tc_pat_len[pat_index] - 1;\
  1138.                                                                 MATCHED = 0;\
  1139.                                                         }\
  1140.                             else if (change_text) {\
  1141.                                 CurrentByteOffset += textbegin - text;\
  1142.                                 text = textbegin;\
  1143.                             }\
  1144.                         }\
  1145.                         else {    /* INVERSE: Don't care about filtering time */\
  1146.                             /* if(lastout < curtextbegin) OUT=1; */\
  1147.                             if (agrep_finalfp != NULL)\
  1148.                                 newlen = quick_tuncompress(FREQ_FILE, STRING_FILE, lastout, curtextbegin - lastout, agrep_finalfp, -1, EASYSEARCH);\
  1149.                             else {\
  1150.                                 if ((newlen = quick_tuncompress(FREQ_FILE, STRING_FILE, lastout, curtextbegin - lastout, agrep_outbuffer, agrep_outlen - agrep_outpointer, EASYSEARCH)) > 0) {\
  1151.                                     if (newlen + agrep_outpointer >= agrep_outlen) {\
  1152.                                         OUTPUT_OVERFLOW;\
  1153.                                         return -1;\
  1154.                                     }\
  1155.                                     agrep_outpointer += newlen;\
  1156.                                 }\
  1157.                             }\
  1158.                             lastout=textbegin;\
  1159.                             if (change_text) {\
  1160.                                 CurrentByteOffset += textbegin - text;\
  1161.                                 text = textbegin;\
  1162.                             }\
  1163.                         }\
  1164.                     }\
  1165.                     else if (change_text) {\
  1166.                         CurrentByteOffset += textbegin - text;\
  1167.                         text = textbegin;\
  1168.                     }\
  1169.                     if (((LIMITOUTPUT > 0) && (LIMITOUTPUT <= num_of_matched)) ||\
  1170.                         ((LIMITPERFILE > 0) && (LIMITPERFILE <= num_of_matched - prev_num_of_matched))) return 0;    /* done */\
  1171.  
  1172.                     DO_OUTPUT(1)
  1173.                 }
  1174.  
  1175.             skip_output:
  1176.                                 if (MATCHED && !MULTI_OUTPUT && !AComplexBoolean) break;    /* else look for more possible matches since we never know how many will match */
  1177.                 if (DOWITHMASK && (text >= curtextend - 1)) {
  1178.                     DOWITHMASK = 0;
  1179.                     if (AComplexBoolean && dd(curtextbegin, curtextend) && eval_tree(AParse, amatched_terminals)) {
  1180.                         DO_OUTPUT(0)
  1181.                     }
  1182.                     if (AParse != 0) memset(amatched_terminals, '\0', anum_terminals);
  1183.                 }
  1184.             }
  1185.             /* If I found some match and I am about to cross over a delimiter, then set DOWITHMASK to 0 and zero out the amatched_terminals */
  1186.             if (DOWITHMASK && (text >= curtextend - 1)) {
  1187.                 DOWITHMASK = 0;
  1188.                 if (AComplexBoolean && dd(curtextbegin, curtextend) && eval_tree(AParse, amatched_terminals)) {
  1189.                     DO_OUTPUT(0)
  1190.                 }
  1191.                 if (AParse != 0) memset(amatched_terminals, '\0', anum_terminals);
  1192.             }
  1193.             if(!MATCHED) shift = 1;    /* || MULTI_OUTPUT is implicit */
  1194.             else {
  1195.                 MATCHED = 0;
  1196.                 shift = m1 - 1 > 0 ? m1 - 1 : 1;
  1197.             }
  1198.         }
  1199.  
  1200.         /* If I found some match and I am about to cross over a delimiter, then set DOWITHMASK to 0 and zero out the amatched_terminals */
  1201.         if (DOWITHMASK && (text >= curtextend - 1)) {
  1202.             DOWITHMASK = 0;
  1203.             if (AComplexBoolean && dd(curtextbegin, curtextend) && eval_tree(AParse, amatched_terminals)) {
  1204.                 DO_OUTPUT(0)
  1205.             }
  1206.             if (AParse != 0) memset(amatched_terminals, '\0', anum_terminals);
  1207.         }
  1208.  
  1209.         text += shift;
  1210.         CurrentByteOffset += shift;
  1211.     }
  1212.  
  1213.     /* Do residual stuff: check if there was a match at the end of the line | check if rest of the buffer needs to be output due to inverse */
  1214.  
  1215.     if (DOWITHMASK && (text >= curtextend - 1)) {
  1216.         DOWITHMASK = 0;
  1217.         if (AComplexBoolean && dd(curtextbegin, curtextend) && eval_tree(AParse, amatched_terminals)) {
  1218.             DO_OUTPUT(0)
  1219.         }
  1220.         if (AParse != 0) memset(amatched_terminals, '\0', anum_terminals);
  1221.     }
  1222.  
  1223.     if (INVERSE && !COUNT && (lastout <= textend)) {
  1224.         if (agrep_finalfp != NULL)
  1225.             newlen = quick_tuncompress(FREQ_FILE, STRING_FILE, lastout, textend - lastout + 1, agrep_finalfp, -1, EASYSEARCH);
  1226.         else {
  1227.             if ((newlen = quick_tuncompress(FREQ_FILE, STRING_FILE, lastout, textend - lastout + 1, agrep_outbuffer, agrep_outlen - agrep_outpointer, EASYSEARCH)) > 0) {
  1228.                 if (newlen + agrep_outpointer >= agrep_outlen) {
  1229.                     OUTPUT_OVERFLOW;
  1230.                     return -1;
  1231.                 }
  1232.                 agrep_outpointer += newlen;
  1233.             }
  1234.         }
  1235.     }
  1236.  
  1237.     return 0;
  1238. }
  1239. #endif    /*DOTCOMPRESSED*/
  1240.  
  1241. /* shift is always 1: slight change in MATCHED semantics: it is set to 1 even if COUNT is set: previously, it wasn't set. Will it effect m_short? */
  1242. int
  1243. m_short(text, start, end)
  1244. int start, end; register uchar *text;
  1245. {
  1246.     int PRINTED = 0;
  1247.     int pat_index;
  1248.         unsigned char *oldtext;
  1249.     register uchar *textend;
  1250.     unsigned char *textbegin;
  1251.     unsigned char *curtextend;
  1252.     unsigned char *curtextbegin;
  1253.     register int p, p_end;
  1254.     int MATCHED=0;
  1255.     /* int OUT=0; */
  1256.     uchar *lastout;
  1257.     uchar *qx;
  1258.     uchar *px;
  1259.     int j;
  1260.     int DOWITHMASK;
  1261.  
  1262.     DOWITHMASK = 0;
  1263.     if (AParse != 0) memset(amatched_terminals, '\0', anum_terminals);
  1264.     textend = text + end;
  1265.     lastout = text + start;
  1266.     textbegin = text + start;
  1267.     text = text + start - 1 ;
  1268. /*
  1269.     if (WORDBOUND || WHOLELINE) text = text-1;
  1270. */
  1271.     if (WHOLELINE) text = text-1;
  1272.         /* to accomodate the extra 2 W_delim */
  1273.     while (++text <= textend) {
  1274.         CurrentByteOffset ++;
  1275.         p = HASH[tr[*text]];
  1276.         p_end = HASH[tr[*text]+1];
  1277.         while(p++ < p_end) {
  1278.             if (((pat_index = pat_indices[p]) <= 0) || (pat_len[pat_index] <= 0)) continue;
  1279. #ifdef    debug
  1280.             printf("m_short(): p=%d pat_index=%d off=%d\n", p, pat_index, textend - text);
  1281. #endif
  1282.             px = PatPtr[p];
  1283.             qx = text;
  1284.             while((*px!=0)&&(tr[*px] == tr[*qx])) {
  1285.                 px++;
  1286.                 qx++;
  1287.             }
  1288.             if (*px == 0) {
  1289.                 if(text >= textend) return 0;
  1290.                 if (WORDBOUND) {
  1291.                     if (isalnum(*qx)) goto skip_output;
  1292.                     if (isalnum(*(text-1))) goto skip_output;
  1293.                 }
  1294.                                 if (!DOWITHMASK) {
  1295.                                         /* Don't update CurrentByteOffset here: only before outputting properly */
  1296.                                         if (!DELIMITER) {
  1297.                         curtextbegin = text; while((curtextbegin > textbegin) && (*(--curtextbegin) != '\n'));
  1298.                         if (*curtextbegin == '\n') curtextbegin ++;
  1299.                         curtextend = text+1; while((curtextend < textend) && (*curtextend != '\n')) curtextend ++;
  1300.                         if (*curtextend == '\n') curtextend ++;
  1301.                                         }
  1302.                                         else {
  1303.                                                 curtextbegin = backward_delimiter(text, textbegin, D_pattern, D_length, OUTTAIL);
  1304.                                                 curtextend = forward_delimiter(text+1, textend, D_pattern, D_length, OUTTAIL);
  1305.                                         }
  1306.                     if (!OUTTAIL || INVERSE) textbegin = curtextend;
  1307.                     else if (DELIMITER) textbegin = curtextend - D_length;
  1308.                     else textbegin = curtextend - 1;
  1309.                                 }
  1310.                                 /* else prev curtextbegin is OK: if full AND isn't found, DOWITHMASK is 0-ed so that we search at most 1 line below */
  1311.                 DOWITHMASK = 1;
  1312.  
  1313.                 amatched_terminals[pat_index - 1] = 1;
  1314.                 if (AComplexBoolean) {
  1315.                     /* Can output only after all the matches in the current record have been identified: just like filter_output */
  1316.                     oldtext = text;
  1317.                     CurrentByteOffset += (oldtext + pat_len[pat_index] - 1 - text);
  1318.                     text = oldtext + pat_len[pat_index] - 1;
  1319.                     MATCHED = 0;
  1320.                     goto skip_output;
  1321.                 }
  1322.                 else if ((long)AParse & AND_EXP) {
  1323.                     for (j=0; j<anum_terminals; j++) if (!amatched_terminals[j]) break;
  1324.                     if (j<anum_terminals) goto skip_output;
  1325.                 }
  1326.  
  1327.                 MATCHED = 1;
  1328.                 oldtext = text; /* used only if MULTI_OUTPUT */
  1329.  
  1330. #undef    DO_OUTPUT
  1331. #define DO_OUTPUT(change_text)\
  1332.                 num_of_matched++;\
  1333.                 if(FILENAMEONLY || SILENT)  return 0;\
  1334.                 if (!COUNT) {\
  1335.                     PRINTED = print_options(pat_index, text, curtextbegin, curtextend);\
  1336.                     if(!INVERSE) {\
  1337.                         if (PRINTRECORD) {\
  1338.                         if (agrep_finalfp != NULL) {\
  1339.                             fwrite(curtextbegin, 1, curtextend - curtextbegin, agrep_finalfp);\
  1340.                         }\
  1341.                         else {\
  1342.                             if (agrep_outpointer + curtextend - curtextbegin >= agrep_outlen) {\
  1343.                                 OUTPUT_OVERFLOW;\
  1344.                                 return -1;\
  1345.                             }\
  1346.                             else {\
  1347.                                 memcpy(agrep_outbuffer + agrep_outpointer, curtextbegin, curtextend-curtextbegin);\
  1348.                                 agrep_outpointer += curtextend - curtextbegin;\
  1349.                             }\
  1350.                         }\
  1351.                         }\
  1352.                         else if (PRINTED) {\
  1353.                             if (agrep_finalfp != NULL) fputc('\n', agrep_finalfp);\
  1354.                             else agrep_outbuffer[agrep_outpointer ++] = '\n';\
  1355.                             PRINTED = 0;\
  1356.                         }\
  1357.                                                 if ((change_text) && MULTI_OUTPUT) {     /* next match starting from end of current */\
  1358.                             CurrentByteOffset += (oldtext + pat_len[pat_index] - 1 - text);\
  1359.                                                         text = oldtext + pat_len[pat_index] - 1;\
  1360.                                                         MATCHED = 0;\
  1361.                                                 }\
  1362.                         else if (change_text) {\
  1363.                             CurrentByteOffset += textbegin - text;\
  1364.                             text = textbegin;\
  1365.                         }\
  1366.                     }\
  1367.                     else {\
  1368.                                                 /* if(lastout < curtextbegin) OUT=1; */\
  1369.                         if (agrep_finalfp != NULL)\
  1370.                             fwrite(lastout, 1, curtextbegin-lastout, agrep_finalfp);\
  1371.                         else {\
  1372.                             if (curtextbegin - lastout + agrep_outpointer >= agrep_outlen) {\
  1373.                                 OUTPUT_OVERFLOW;\
  1374.                                 return -1;\
  1375.                             }\
  1376.                             memcpy(agrep_outbuffer+agrep_outpointer, lastout, curtextbegin-lastout);\
  1377.                             agrep_outpointer += (curtextbegin-lastout);\
  1378.                         }\
  1379.                                                 lastout=textbegin;\
  1380.                         if (change_text) {\
  1381.                             CurrentByteOffset += textbegin - text;\
  1382.                             text = textbegin;\
  1383.                         }\
  1384.                     }\
  1385.                 }\
  1386.                 else if (change_text) {\
  1387.                     CurrentByteOffset += textbegin - text;\
  1388.                     text = textbegin;\
  1389.                 }\
  1390.                 if (((LIMITOUTPUT > 0) && (LIMITOUTPUT <= num_of_matched)) ||\
  1391.                     ((LIMITPERFILE > 0) && (LIMITPERFILE <= num_of_matched - prev_num_of_matched))) return 0;    /* done */\
  1392.  
  1393.                 DO_OUTPUT(1)
  1394.             }
  1395.  
  1396.         skip_output:
  1397.                         if(MATCHED && !MULTI_OUTPUT && !AComplexBoolean) break;     /* else look for more possible matches */
  1398.             if (DOWITHMASK && (text >= curtextend - 1)) {
  1399.                 DOWITHMASK = 0;
  1400.                 if (AComplexBoolean && dd(curtextbegin, curtextend) && eval_tree(AParse, amatched_terminals)) {
  1401.                     DO_OUTPUT(0)
  1402.                 }
  1403.                 if (AParse != 0) memset(amatched_terminals, '\0', anum_terminals);
  1404.             }
  1405.         }
  1406.         /* If I found some match and I am about to cross over a delimiter, then set DOWITHMASK to 0 and zero out the amatched_terminals */
  1407.         if (DOWITHMASK && (text >= curtextend - 1)) {
  1408.             DOWITHMASK = 0;
  1409.             if (AComplexBoolean && dd(curtextbegin, curtextend) && eval_tree(AParse, amatched_terminals)) {
  1410.                 DO_OUTPUT(0)
  1411.             }
  1412.             if (AParse != 0) memset(amatched_terminals, '\0', anum_terminals);
  1413.         }
  1414.         if (MATCHED) text --;
  1415.         MATCHED = 0;
  1416.     } /* while */
  1417.     CurrentByteOffset ++;
  1418.  
  1419.     /* Do residual stuff: check if there was a match at the end of the line | check if rest of the buffer needs to be output due to inverse */
  1420.  
  1421.     if (DOWITHMASK && (text >= curtextend - 1)) {
  1422.         DOWITHMASK = 0;
  1423.         if (AComplexBoolean && dd(curtextbegin, curtextend) && eval_tree(AParse, amatched_terminals)) {
  1424.             DO_OUTPUT(0)
  1425.         }
  1426.         if (AParse != 0) memset(amatched_terminals, '\0', anum_terminals);
  1427.     }
  1428.  
  1429.         if(INVERSE && !COUNT && (lastout <= textend)) {
  1430.                 if (agrep_finalfp != NULL) {
  1431.                         while(lastout <= textend) fputc(*lastout++, agrep_finalfp);
  1432.                 }
  1433.                 else {
  1434.                         if (textend - lastout + 1 + agrep_outpointer >= agrep_outlen) {
  1435.                                 OUTPUT_OVERFLOW;
  1436.                                 return -1;
  1437.                         }
  1438.                         memcpy(agrep_outbuffer+agrep_outpointer, lastout, text-lastout+1);
  1439.                         agrep_outpointer += (text-lastout+1);
  1440.                         lastout = textend;
  1441.                 }
  1442.         }
  1443.  
  1444.         return 0;
  1445. }
  1446.  
  1447. #if    DOTCOMPRESSED
  1448. /* shift is always 1: slight change in MATCHED semantics: it is set to 1 even if COUNT is set: previously, it wasn't set. Will it effect m_short? */
  1449. int
  1450. tc_m_short(text, start, end)
  1451. int start, end; register uchar *text;
  1452. {
  1453.     int PRINTED = 0;
  1454.     int pat_index;
  1455.         unsigned char *oldtext;
  1456.     register uchar *textend;
  1457.     unsigned char *textbegin;
  1458.     unsigned char *curtextend;
  1459.     unsigned char *curtextbegin;
  1460.     register int p, p_end;
  1461.     int MATCHED=0;
  1462.     /* int OUT=0; */
  1463.     uchar *lastout;
  1464.     uchar *qx;
  1465.     uchar *px;
  1466.     int j;
  1467.     int DOWITHMASK;
  1468.     struct timeval initt, finalt;
  1469.     int newlen;
  1470.  
  1471.     DOWITHMASK = 0;
  1472.     if (AParse != 0) memset(amatched_terminals, '\0', anum_terminals);
  1473.     textend = text + end;
  1474.     lastout = text + start;
  1475.     text = text + start - 1 ;
  1476.     textbegin = text + start;
  1477.     /* WORDBOUND adjustment not required */
  1478.     while (++text <= textend) {
  1479.         CurrentByteOffset ++;
  1480.         p = tc_HASH[tc_tr[*text]];
  1481.         p_end = tc_HASH[tc_tr[*text]+1];
  1482.         while(p++ < p_end) {
  1483.             if (((pat_index = tc_pat_indices[p]) <= 0) || (tc_pat_len[pat_index] <= 0)) continue;
  1484. #ifdef    debug
  1485.             printf("m_short(): p=%d pat_index=%d off=%d\n", p, pat_index, textend - text);
  1486. #endif
  1487.             px = tc_PatPtr[p];
  1488.             qx = text;
  1489.             while((*px!=0)&&(tc_tr[*px] == tc_tr[*qx])) {
  1490.                 px++;
  1491.                 qx++;
  1492.             }
  1493.             if (*px == 0) {
  1494.                 if(text >= textend) return 0;
  1495.  
  1496.                 if (!DOWITHMASK) {
  1497.                     /* Don't update CurrentByteOffset here: only before outputting properly */
  1498.                     if (!DELIMITER) {
  1499.                         curtextbegin = text; while((curtextbegin > textbegin) && (*(--curtextbegin) != '\n'));
  1500.                         if (*curtextbegin == '\n') curtextbegin ++;
  1501.                         curtextend = text+1; while((curtextend < textend) && (*curtextend != '\n')) curtextend ++;
  1502.                         if (*curtextend == '\n') curtextend ++;
  1503.                     }
  1504.                     else {
  1505.                         curtextbegin = backward_delimiter(text, textbegin, tc_D_pattern, tc_D_length, OUTTAIL);
  1506.                         curtextend = forward_delimiter(text+1, textend, tc_D_pattern, tc_D_length, OUTTAIL);
  1507.                     }
  1508.                 }
  1509.                 /* else prev curtextbegin is OK: if full AND isn't found, DOWITHMASK is 0-ed so that we search at most 1 line below */
  1510. #if    MEASURE_TIMES
  1511.                 gettimeofday(&initt, NULL);
  1512. #endif    /*MEASURE_TIMES*/
  1513.                 /* Was it really a match in the compressed line from prev line in text to text + strlen(tc_pat_len[pat_index]? */
  1514.                 if (-1 == exists_tcompressed_word(tc_PatPtr[p], tc_pat_len[pat_index], curtextbegin, text - curtextbegin + tc_pat_len[pat_index], EASYSEARCH))
  1515.                     goto skip_output;
  1516. #if     MEASURE_TIMES
  1517.                 gettimeofday(&finalt, NULL);
  1518.                 FILTERALGO_ms +=  (finalt.tv_sec *1000 + finalt.tv_usec/1000) - (initt.tv_sec*1000 + initt.tv_usec/1000);
  1519. #endif  /*MEASURE_TIMES*/
  1520.  
  1521.                 if (!DOWITHMASK) {
  1522.                     if (!OUTTAIL || INVERSE) textbegin = curtextend;
  1523.                     else if (DELIMITER) textbegin = curtextend - D_length;
  1524.                     else textbegin = curtextend - 1;
  1525.                 }
  1526.                 DOWITHMASK = 1;
  1527.                 amatched_terminals[pat_index-1] = 1;
  1528.                 if (AComplexBoolean) {
  1529.                     /* Can output only after all the matches in the current record have been identified: just like filter_output */
  1530.                     oldtext = text;
  1531.                     CurrentByteOffset += (oldtext + pat_len[pat_index] - 1 - text);
  1532.                     text = oldtext + pat_len[pat_index] - 1;
  1533.                     MATCHED = 0;
  1534.                     goto skip_output;
  1535.                 }
  1536.                 else if ((long)AParse & AND_EXP) {
  1537.                     for (j=0; j<anum_terminals; j++) if (!amatched_terminals[j]) break;
  1538.                     if (j<anum_terminals) goto skip_output;
  1539.                 }
  1540.  
  1541.                 MATCHED = 1;
  1542.                 oldtext = text; /* used only if MULTI_OUTPUT */
  1543.  
  1544. #undef    DO_OUTPUT
  1545. #define DO_OUTPUT(change_text)\
  1546.                 num_of_matched++;\
  1547.                 if(FILENAMEONLY || SILENT)  return 0;\
  1548.                 if (!COUNT) {\
  1549.                     PRINTED = print_options(pat_index, text, curtextbegin, curtextend);\
  1550.                     if(!INVERSE) {\
  1551.                         if (PRINTRECORD) {\
  1552. /* #if     MEASURE_TIMES\
  1553.                         gettimeofday(&initt, NULL);\
  1554. #endif  MEASURE_TIMES*/\
  1555.                         if (agrep_finalfp != NULL)\
  1556.                             newlen = quick_tuncompress(FREQ_FILE, STRING_FILE, curtextbegin, curtextend-curtextbegin, agrep_finalfp, -1, EASYSEARCH);\
  1557.                         else {\
  1558.                             if ((newlen = quick_tuncompress(FREQ_FILE, STRING_FILE, curtextbegin, curtextend-curtextbegin, agrep_outbuffer, agrep_outlen - agrep_outpointer, EASYSEARCH)) > 0) {\
  1559.                                 if (newlen + agrep_outpointer >= agrep_outlen) {\
  1560.                                     OUTPUT_OVERFLOW;\
  1561.                                     return -1;\
  1562.                                 }\
  1563.                                 agrep_outpointer += newlen;\
  1564.                             }\
  1565.                         }\
  1566. /*#if     MEASURE_TIMES\
  1567.                         gettimeofday(&finalt, NULL);\
  1568.                         OUTFILTER_ms +=  (finalt.tv_sec* 1000 + finalt.tv_usec/1000) - (initt.tv_sec*1000 + initt.tv_usec/1000);\
  1569. #endif  MEASURE_TIMES*/\
  1570.                         }\
  1571.                         else if (PRINTED) {\
  1572.                             if (agrep_finalfp != NULL) fputc('\n', agrep_finalfp);\
  1573.                             else agrep_outbuffer[agrep_outpointer ++] = '\n';\
  1574.                             PRINTED = 0;\
  1575.                         }\
  1576.                         if ((change_text) && MULTI_OUTPUT) {     /* next match starting from end of current */\
  1577.                             CurrentByteOffset += (oldtext + tc_pat_len[pat_index] - 1 - text);\
  1578.                             text = oldtext + tc_pat_len[pat_index] - 1;\
  1579.                             MATCHED = 0;\
  1580.                         }\
  1581.                         else if (change_text) {\
  1582.                             CurrentByteOffset += textbegin - text;\
  1583.                             text = textbegin;\
  1584.                         }\
  1585.                     }\
  1586.                     else {    /* INVERSE: Don't care about filtering time */\
  1587.                         /* if(lastout < curtextbegin) OUT=1; */\
  1588.                         if (agrep_finalfp != NULL)\
  1589.                             newlen = quick_tuncompress(FREQ_FILE, STRING_FILE, lastout, curtextbegin - lastout, agrep_finalfp, -1, EASYSEARCH);\
  1590.                         else {\
  1591.                             if ((newlen = quick_tuncompress(FREQ_FILE, STRING_FILE, lastout, curtextbegin - lastout, agrep_outbuffer, agrep_outlen - agrep_outpointer, EASYSEARCH)) > 0) {\
  1592.                                 if (newlen + agrep_outpointer >= agrep_outlen) {\
  1593.                                     OUTPUT_OVERFLOW;\
  1594.                                     return -1;\
  1595.                                 }\
  1596.                                 agrep_outpointer += newlen;\
  1597.                             }\
  1598.                         }\
  1599.                         lastout=textbegin;\
  1600.                         if (change_text) {\
  1601.                             CurrentByteOffset += textbegin - text;\
  1602.                             text = textbegin;\
  1603.                         }\
  1604.                     }\
  1605.                 }\
  1606.                 else if (change_text) {\
  1607.                     CurrentByteOffset += textbegin - text;\
  1608.                     text = textbegin;\
  1609.                 }\
  1610.                 if (((LIMITOUTPUT > 0) && (LIMITOUTPUT <= num_of_matched)) ||\
  1611.                     ((LIMITPERFILE > 0) && (LIMITPERFILE <= num_of_matched - prev_num_of_matched))) return 0;    /* done */\
  1612.  
  1613.                 DO_OUTPUT(1)
  1614.             }
  1615.  
  1616.         skip_output:
  1617.                         if(MATCHED && !MULTI_OUTPUT && !AComplexBoolean) break;     /* else look for more possible matches */
  1618.             if (DOWITHMASK && (text >= curtextend - 1)) {
  1619.                 DOWITHMASK = 0;
  1620.                 if (AComplexBoolean && dd(curtextbegin, curtextend) && eval_tree(AParse, amatched_terminals)) {
  1621.                     DO_OUTPUT(0)
  1622.                 }
  1623.                 if (AParse != 0) memset(amatched_terminals, '\0', anum_terminals);
  1624.             }
  1625.         }
  1626.         /* If I found some match and I am about to cross over a delimiter, then set DOWITHMASK to 0 and zero out the amatched_terminals */
  1627.         if (DOWITHMASK && (text >= curtextend - 1)) {
  1628.             DOWITHMASK = 0;
  1629.             if (AComplexBoolean && dd(curtextbegin, curtextend) && eval_tree(AParse, amatched_terminals)) {
  1630.                 DO_OUTPUT(0)
  1631.             }
  1632.             if (AParse != 0) memset(amatched_terminals, '\0', anum_terminals);
  1633.         }
  1634.         if (MATCHED) text--;
  1635.         MATCHED = 0;
  1636.     } /* while */
  1637.     CurrentByteOffset ++;
  1638.  
  1639.     /* Do residual stuff: check if there was a match at the end of the line | check if rest of the buffer needs to be output due to inverse */
  1640.  
  1641.     if (DOWITHMASK && (text >= curtextend - 1)) {
  1642.         DOWITHMASK = 0;
  1643.         if (AComplexBoolean && dd(curtextbegin, curtextend) && eval_tree(AParse, amatched_terminals)) {
  1644.             DO_OUTPUT(0)
  1645.         }
  1646.         if (AParse != 0) memset(amatched_terminals, '\0', anum_terminals);
  1647.     }
  1648.  
  1649.     if (INVERSE && !COUNT && (lastout <= textend)) {
  1650.         if (agrep_finalfp != NULL)
  1651.             newlen = quick_tuncompress(FREQ_FILE, STRING_FILE, lastout, textend - lastout + 1, agrep_finalfp, -1, EASYSEARCH);
  1652.         else {
  1653.             if ((newlen = quick_tuncompress(FREQ_FILE, STRING_FILE, lastout, textend - lastout + 1, agrep_outbuffer, agrep_outlen - agrep_outpointer, EASYSEARCH)) > 0) {
  1654.                 if (newlen + agrep_outpointer >= agrep_outlen) {
  1655.                     OUTPUT_OVERFLOW;
  1656.                     return -1;
  1657.                 }
  1658.                 agrep_outpointer += newlen;
  1659.             }
  1660.         }
  1661.     }
  1662.  
  1663.         return 0;
  1664. }
  1665. #endif    /*DOTCOMPRESSED*/
  1666.  
  1667. static void
  1668. f_prep(pat_index, Pattern)
  1669. uchar *Pattern;   int pat_index;
  1670. {
  1671. int i, m;
  1672. register unsigned hash=0;
  1673. #ifdef debug
  1674.     puts(Pattern);
  1675. #endif
  1676.     m = p_size;
  1677.         for (i=m-1; i>=(1+LONG); i--) {
  1678.                 hash = (tr1[Pattern[i]]);
  1679.                 hash = (hash << Hbits) + (tr1[Pattern[i-1]]);
  1680.         if(LONG) hash = (hash << Hbits) + (tr1[Pattern[i-2]] );
  1681.         if(SHIFT1[hash] >= m-1-i) SHIFT1[hash] = m-1-i;
  1682.     }
  1683.     i=m-1;
  1684.         hash = (tr1[Pattern[i]]);
  1685.         hash = (hash << Hbits) + (tr1[Pattern[i-1]]);
  1686.     if(LONG) hash = (hash << Hbits) + (tr1[Pattern[i-2]] );
  1687.         if(SHORT) hash=tr[Pattern[0]];
  1688. #ifdef debug
  1689.     printf("hash = %d\n", hash);
  1690. #endif
  1691.         HASH[hash]++;
  1692.         return;
  1693. }
  1694.  
  1695. #if    DOTCOMPRESSED
  1696. static void
  1697. tc_f_prep(pat_index, Pattern)
  1698. uchar *Pattern;   int pat_index;
  1699. {
  1700. int i, m;
  1701. register unsigned hash=0;
  1702. #ifdef debug
  1703.     puts(Pattern);
  1704. #endif
  1705.     m = tc_p_size;
  1706.         for (i=m-1; i>=(1+tc_LONG); i--) {
  1707.                 hash = (tc_tr1[Pattern[i]]);
  1708.                 hash = (hash << Hbits) + (tc_tr1[Pattern[i-1]]);
  1709.         if(tc_LONG) hash = (hash << Hbits) + (tc_tr1[Pattern[i-2]] );
  1710.         if(tc_SHIFT1[hash] >= m-1-i) tc_SHIFT1[hash] = m-1-i;
  1711.     }
  1712.     i=m-1;
  1713.         hash = (tc_tr1[Pattern[i]]);
  1714.         hash = (hash << Hbits) + (tc_tr1[Pattern[i-1]]);
  1715.     if(tc_LONG) hash = (hash << Hbits) + (tc_tr1[Pattern[i-2]] );
  1716.         if(tc_SHORT) hash=tc_tr[Pattern[0]];
  1717. #ifdef debug
  1718.     printf("hash = %d\n", hash);
  1719. #endif
  1720.         tc_HASH[hash]++;
  1721.         return;
  1722. }
  1723. #endif    /*DOTCOMPRESSED*/
  1724.  
  1725. static void
  1726. f_prep1(pat_index, Pattern)
  1727. uchar *Pattern;   int pat_index;
  1728. {
  1729. int i, m;
  1730. int hash2;
  1731. register unsigned hash;
  1732.     m = p_size;
  1733. #ifdef debug
  1734.     puts(Pattern);
  1735. #endif
  1736.         for (i=m-1; i>=(1+LONG); i--) {
  1737.                 hash = (tr1[Pattern[i]]);
  1738.                 hash = (hash << Hbits) + (tr1[Pattern[i-1]]);
  1739.         if(LONG) hash = (hash << Hbits) + (tr1[Pattern[i-2]] );
  1740.         if(SHIFT1[hash] >= m-1-i) SHIFT1[hash] = m-1-i;
  1741.     }
  1742.     i=m-1;
  1743.         hash = (tr1[Pattern[i]]);
  1744.         hash = (hash << Hbits) + (tr1[Pattern[i-1]]);
  1745.     if(LONG) hash = (hash << Hbits) + (tr1[Pattern[i-2]] );
  1746.         if(SHORT) hash=tr[Pattern[0]];
  1747.     hash2 = (tr[Pattern[0]] << 8) + tr[Pattern[1]];
  1748. #ifdef debug
  1749.     printf("hash = %d, HASH[hash] = %d\n", hash, HASH[hash]);
  1750. #endif
  1751.         PatPtr[HASH[hash]] = Pattern;
  1752.         pat_indices[HASH[hash]] = pat_index;
  1753.     Hash2[HASH[hash]] = hash2;
  1754.         HASH[hash]--;
  1755.         return;
  1756. }
  1757.  
  1758. #if    DOTCOMPRESSED
  1759. static void
  1760. tc_f_prep1(pat_index, Pattern)
  1761. uchar *Pattern;   int pat_index;
  1762. {
  1763. int i, m;
  1764. int hash2;
  1765. register unsigned hash;
  1766.     m = tc_p_size;
  1767. #ifdef debug
  1768.     puts(Pattern);
  1769. #endif
  1770.         for (i=m-1; i>=(1+tc_LONG); i--) {
  1771.                 hash = (tc_tr1[Pattern[i]]);
  1772.                 hash = (hash << Hbits) + (tc_tr1[Pattern[i-1]]);
  1773.         if(tc_LONG) hash = (hash << Hbits) + (tc_tr1[Pattern[i-2]] );
  1774.         if(tc_SHIFT1[hash] >= m-1-i) tc_SHIFT1[hash] = m-1-i;
  1775.     }
  1776.     i=m-1;
  1777.         hash = (tc_tr1[Pattern[i]]);
  1778.         hash = (hash << Hbits) + (tc_tr1[Pattern[i-1]]);
  1779.     if(tc_LONG) hash = (hash << Hbits) + (tc_tr1[Pattern[i-2]] );
  1780.         if(tc_SHORT) hash=tc_tr[Pattern[0]];
  1781.     hash2 = (tc_tr[Pattern[0]] << 8) + tc_tr[Pattern[1]];
  1782. #ifdef debug
  1783.     printf("hash = %d, tc_HASH[hash] = %d\n", hash, tc_HASH[hash]);
  1784. #endif
  1785.         tc_PatPtr[tc_HASH[hash]] = Pattern;
  1786.         tc_pat_indices[tc_HASH[hash]] = pat_index;
  1787.     tc_Hash2[tc_HASH[hash]] = hash2;
  1788.         tc_HASH[hash]--;
  1789.         return;
  1790. }
  1791. #endif    /*DOTCOMPRESSED*/
  1792.  
  1793. static void
  1794. accumulate()
  1795. {
  1796.     int i;
  1797.  
  1798.     for(i=1; i<MAXHASH; i++)  {
  1799.     /*
  1800.     printf("%d, ", HASH[i]);
  1801.     */
  1802.     HASH[i] = HASH[i-1] + HASH[i];
  1803.     }
  1804.     HASH[0] = 0;
  1805.     return;
  1806. }
  1807.  
  1808. #if    DOTCOMPRESSED
  1809. static void
  1810. tc_accumulate()
  1811. {
  1812.     int i;
  1813.  
  1814.     for(i=1; i<MAXHASH; i++)  {
  1815.     /*
  1816.     printf("%d, ", HASH[i]);
  1817.     */
  1818.     tc_HASH[i] = tc_HASH[i-1] + tc_HASH[i];
  1819.     }
  1820.     tc_HASH[0] = 0;
  1821.     return;
  1822. }
  1823. #endif    /*DOTCOMPRESSED*/
  1824.  
  1825.  
  1826.